package top.codef.secure.login;

import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import top.codef.secure.exceptions.CerberusAuthenticationException;
import top.codef.secure.properties.CerberusCustomLoginParam;
import top.codef.secure.properties.CerberusCustomLoginProperties;

public class CerberusLoginFilter extends UsernamePasswordAuthenticationFilter {

	@Autowired
	private final CerberusCustomLoginProperties cerberusCustomLoginProperties;

	public CerberusLoginFilter(CerberusCustomLoginProperties cerberusCustomLoginProperties) {
		this.cerberusCustomLoginProperties = cerberusCustomLoginProperties;
	}

	@Override
	public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
			throws AuthenticationException {

		String optional = request.getParameter(cerberusCustomLoginProperties.getOptionParam());
		optional = optional == null ? "default" : optional;
		CerberusCustomLoginParam param = cerberusCustomLoginProperties.getParams().get(optional);
		if (param == null)
			throw new CerberusAuthenticationException("no such option：" + optional);
		String principal = request.getParameter(param.getPrincipalParam());
		String credentials = request.getParameter(param.getCredentialParam());
		principal = principal == null ? "" : principal.trim();
		Map<String, Object> headerParam = new HashMap<>();
		param.getHeaderParamKeys().forEach(x -> {
			String value = request.getHeader(x.toLowerCase());
			if (value != null)
				headerParam.put(x, value);
		});
		CerberusAuthenticationToken cerberusAuthenticationToken = new CerberusAuthenticationToken(principal,
				credentials, optional, headerParam);
		setDetails(request, cerberusAuthenticationToken);
		return getAuthenticationManager().authenticate(cerberusAuthenticationToken);
	}

	private void setDetails(HttpServletRequest request, AbstractAuthenticationToken authRequest) {
		authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
	}

}
